home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CD ROM Paradise Collection 4
/
CD ROM Paradise Collection 4 1995 Nov.iso
/
edit
/
thesrc20.zip
/
target.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-01-26
|
64KB
|
1,740 lines
/***********************************************************************/
/* TARGET.C - Functions related to targets. */
/***********************************************************************/
/*
* THE - The Hessling Editor. A text editor similar to VM/CMS xedit.
* Copyright (C) 1991-1995 Mark Hessling
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to:
*
* The Free Software Foundation, Inc.
* 675 Mass Ave,
* Cambridge, MA 02139 USA.
*
*
* If you make modifications to this software that you feel increases
* it usefulness for the rest of the community, please email the
* changes, enhancements, bug fixes as well as any and all ideas to me.
* This software is going to be maintained and enhanced as deemed
* necessary by the community.
*
* Mark Hessling email: M.Hessling@gu.edu.au
* 36 David Road Phone: +61 7 849 7731
* Holland Park Fax: +61 7 875 5314
* QLD 4121
* Australia
*/
/*
$Id: target.c 2.0 1995/01/26 16:32:04 MH Release MH $
*/
#include <stdio.h>
#include "the.h"
#include "proto.h"
#define STATE_START 0
#define STATE_DELIM 1
#define STATE_STRING 2
#define STATE_BOOLEAN 3
#define STATE_NEXT 4
#define STATE_POINT 5
#define STATE_ABSOLUTE 6
#define STATE_RELATIVE 7
#define STATE_POSITIVE 8
#define STATE_NEGATIVE 9
#define STATE_SPARE 10
#define STATE_QUIT 98
#define STATE_ERROR 99
#ifdef PROTO
static bool is_blank(LINE *);
#else
static bool is_blank();
#endif
/***********************************************************************/
#ifdef PROTO
short split_change_params(CHARTYPE *cmd_line,CHARTYPE **old_str,CHARTYPE **new_str,
TARGET *target,LINETYPE *num,LINETYPE *occ)
#else
short split_change_params(cmd_line,old_str,new_str,target,num,occ)
CHARTYPE *cmd_line,**old_str,**new_str;
TARGET *target;
LINETYPE *num,*occ;
#endif
/***********************************************************************/
{
/*-------------------------- external data ----------------------------*/
/*--------------------------- local data ------------------------------*/
#define SCP_PARAMS 2
CHARTYPE *word[SCP_PARAMS+1];
register short i=0,j=0;
CHARTYPE *target_start=NULL;
short rc=RC_OK;
CHARTYPE delim=' ';
short idx=0;
short target_type = TARGET_NORMAL|TARGET_BLOCK_CURRENT|TARGET_ALL|TARGET_SPARE;
unsigned short num_params=0;
/*--------------------------- processing ------------------------------*/
#ifdef TRACE
trace_function("target.c: split_change_params");
#endif
/*---------------------------------------------------------------------*/
/* First, determine the delimiter; the first character in the argument */
/* string. */
/*---------------------------------------------------------------------*/
delim = *(cmd_line);
/*---------------------------------------------------------------------*/
/* Set up default values for the return values... */
/*---------------------------------------------------------------------*/
*old_str = cmd_line+1;
*new_str = (CHARTYPE *)"";
target_start = (CHARTYPE *)"";
*num = *occ = 1L;
target->num_lines = 1L;
target->true_line = get_true_line();
/*---------------------------------------------------------------------*/
/* Set up default values for the return values... */
/*---------------------------------------------------------------------*/
idx = strlen(cmd_line);
for (i=1,j=0;i<idx;i++)
{
if (*(cmd_line+i) == delim)
{
j++;
switch(j)
{
case 1:
*(cmd_line+i) = '\0';
*new_str = cmd_line+i+1;
break;
case 2:
*(cmd_line+i) = '\0';
target_start = cmd_line+i+1;
break;
default:
break;
}
}
if (j == 2)
break;
}
/*---------------------------------------------------------------------*/
/* Check to see if there is a target, if not return here. */
/*---------------------------------------------------------------------*/
if (blank_field(target_start))
{
#ifdef TRACE
trace_return();
#endif
return(RC_OK);
}
/*---------------------------------------------------------------------*/
/* Parse and validate the target... */
/*---------------------------------------------------------------------*/
if ((rc = validate_target(target_start,target,target_type,get_true_line(),TRUE,TRUE)) != RC_OK)
{
#ifdef TRACE
trace_return();
#endif
return(rc);
}
/*---------------------------------------------------------------------*/
/* Check to see if there are further arguments after the target... */
/*---------------------------------------------------------------------*/
if (target->spare == (-1))
{
#ifdef TRACE
trace_return();
#endif
return(RC_OK);
}
/*---------------------------------------------------------------------*/
/* Validate the arguments following the target... */
/*---------------------------------------------------------------------*/
num_params = param_split(strtrunc(target->rt[target->spare].string),word,SCP_PARAMS,WORD_DELIMS,TEMP_PARAM);
if (num_params == 1
|| num_params == 2)
{
if (strcmp(word[0],"*") == 0)
*num = MAX_LONG;
else
if (!valid_positive_integer(word[0]))
{
display_error(4,word[0],FALSE);
#ifdef TRACE
trace_return();
#endif
return(RC_INVALID_OPERAND);
}
else
*num = atol(word[0]);
}
if (num_params == 2)
{
if (!valid_positive_integer(word[1]))
{
display_error(4,word[1],FALSE);
#ifdef TRACE
trace_return();
#endif
return(RC_INVALID_OPERAND);
}
else
*occ = atol(word[1]);
}
#ifdef TRACE
trace_return();
#endif
return(RC_OK);
}
/***********************************************************************/
#ifdef PROTO
short parse_target(CHARTYPE *target_spec,LINETYPE true_line,
TARGET *target,short target_types,bool display_parse_error,
bool allow_error_display)
#else
short parse_target(target_spec,true_line,target,target_types,display_parse_error,allow_error_display)
CHARTYPE *target_spec;
LINETYPE true_line;
TARGET *target;
short target_types;
bool display_parse_error,allow_error_display;
#endif
/***********************************************************************/
{
/*-------------------------- external data ----------------------------*/
/*--------------------------- local data ------------------------------*/
short num_targets=0;
CHARTYPE boolean=' ';
short state=STATE_NEXT;
short len=0,inc=0,target_length=strlen(target_spec),off=0;
CHARTYPE delim=' ';
register short i=0;
register short j=0;
short str_start=0,str_end=0;
short rtarget=0,rc=RC_OK;
short potential_spare_start=0;
bool negative=FALSE;
CHARTYPE *ptr=NULL;
LINETYPE lineno=0L;
/*--------------------------- processing ------------------------------*/
#ifdef TRACE
trace_function("target.c: parse_target");
#endif
/*---------------------------------------------------------------------*/
/* Copy the incoming target specification... */
/*---------------------------------------------------------------------*/
if ((target->string = (CHARTYPE *)my_strdup(target_spec)) == NULL)
{
if (allow_error_display)
display_error(30,(CHARTYPE *)"",FALSE);
#ifdef TRACE
trace_return();
#endif
return(RC_OUT_OF_MEMORY);
}
ptr = target->string;
/*---------------------------------------------------------------------*/
/* Parse the target... */
/*---------------------------------------------------------------------*/
while(1)
{
inc = 1;
switch(state)
{
case STATE_NEXT:
if (target->rt == NULL)
target->rt = (RTARGET *)(*the_malloc)((num_targets+1)*sizeof(RTARGET));
else
target->rt = (RTARGET *)(*the_realloc)(target->rt,(num_targets+1)*sizeof(RTARGET));
if (target->rt == NULL)
{
if (allow_error_display)
display_error(30,(CHARTYPE *)"",FALSE);
#ifdef TRACE
trace_return();
#endif
return(RC_OUT_OF_MEMORY);
}
target->rt[num_targets].not = FALSE;
target->rt[num_targets].boolean = boolean;
target->rt[num_targets].length = 0;
target->rt[num_targets].string = NULL;
target->rt[num_targets].negative = FALSE;
target->rt[num_targets].target_type = TARGET_ERR;
if (target->spare != (-1))
state = STATE_SPARE;
else
state = STATE_START;
inc = 0;
break;
case STATE_START:
switch(*(ptr+i))
{
case '~': case '^':
if (target->rt[num_targets].not)
{
state = STATE_ERROR;
inc = 0;
break;
}
target->rt[num_targets].not = TRUE;
break;
case ' ':
case '\t':
break;
case '-':
if (target->rt[num_targets].negative)
{
state = STATE_ERROR;
inc = 0;
break;
}
target->rt[num_targets].negative = TRUE;
state = STATE_NEGATIVE;
break;
case '+':
if (target->rt[num_targets].negative)
{
state = STATE_ERROR;
inc = 0;
break;
}
inc = 1;
break;
case '.':
if (target->rt[num_targets].negative)
{
state = STATE_ERROR;
inc = 0;
break;
}
state = STATE_POINT;
str_start = i;
break;
case '*':
state = STATE_BOOLEAN;
target->rt[num_targets].target_type = TARGET_RELATIVE;
target->rt[num_targets].string = (CHARTYPE *)(*the_malloc)(3);
if (target->rt[num_targets].string == NULL)
{
if (allow_error_display)
display_error(30,(CHARTYPE *)"",FALSE);
#ifdef TRACE
trace_return();
#endif
return(RC_OUT_OF_MEMORY);
}
if (target->rt[num_targets].negative)
{
target->rt[num_targets].numeric_target = true_line*(-1L);
strcpy(target->rt[num_targets].string,"-*");
}
else
{
target->rt[num_targets].numeric_target = (CURRENT_FILE->number_lines - true_line) + 2;
strcpy(target->rt[num_targets].string,"*");
}
inc = 1;
potential_spare_start = i+1;
num_targets++;
break;
case ':': case ';':
state = STATE_ABSOLUTE;
delim = *(ptr+i);
str_start = i+1;
break;
case '/': case '\\': case '@':
state = STATE_STRING;
str_start = i+1;
delim = *(ptr+i);
break;
case 'a': case 'A':
if (target->rt[num_targets].not
|| target->rt[num_targets].negative)
{
state = STATE_ERROR;
inc = 0;
break;
}
if (target_length-i < 3)
{
target->rt[num_targets].target_type = TARGET_ERR;
state = STATE_ERROR;
inc = 0;
break;
}
if (memcmpi("all",ptr+i,3) == 0
&& (*(ptr+(i+3)) == ' '
|| *(ptr+(i+3)) == '\0'
|| *(ptr+(i+3)) == '\t'))
{
target->rt[num_targets].target_type = TARGET_ALL;
inc = 3;
state = STATE_BOOLEAN;
num_targets++;
potential_spare_start = i+3;
break;
}
state = STATE_ERROR;
inc = 0;
break;
case 'b': case 'B':
if (target_length-i < 5)
{
state = STATE_ERROR;
inc = 0;
break;
}
if (memcmpi("blank",ptr+i,5) == 0
&& (*(ptr+(i+5)) == ' '
|| *(ptr+(i+5)) == '\0'
|| *(ptr+(i+5)) == '\t'))
{
target->rt[num_targets].target_type = TARGET_BLANK;
inc = 5;
potential_spare_start = i+5;
state = STATE_BOOLEAN;
num_targets++;
break;
}
if (target->rt[num_targets].not
|| target->rt[num_targets].negative)
{
state = STATE_ERROR;
inc = 0;
break;
}
if (memcmpi("block",ptr+i,5) == 0
&& (*(ptr+(i+5)) == ' '
|| *(ptr+(i+5)) == '\0'
|| *(ptr+(i+5)) == '\t'))
{
target->rt[num_targets].target_type = TARGET_BLOCK;
inc = 5;
potential_spare_start = i+5;
state = STATE_BOOLEAN;
num_targets++;
break;
}
state = STATE_ERROR;
inc = 0;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
state = STATE_RELATIVE;
str_start = i;
delim = '\0';
inc = 0;
break;
default:
state = STATE_ERROR;
inc = 0;
break;
}
break;
case STATE_STRING:
switch(*(ptr+i))
{
case '/': case '\\': case '@':
case '\0':
if (*(ptr+i) == delim
|| *(ptr+i) == '\0')
{
state = STATE_BOOLEAN;
str_end = i;
len = str_end-str_start;
target->rt[num_targets].string = (CHARTYPE *)(*the_malloc)(len+1);
if (target->rt[num_targets].string == NULL)
{
if (allow_error_display)
display_error(30,(CHARTYPE *)"",FALSE);
#ifdef TRACE
trace_return();
#endif
return(RC_OUT_OF_MEMORY);
}
memcpy(target->rt[num_targets].string,ptr+str_start,len);
target->rt[num_targets].string[len] = '\0';
target->rt[num_targets].length = len;
target->rt[num_targets].target_type = TARGET_STRING;
potential_spare_start = i+1;
num_targets++;
}
break;
default:
break;
}
break;
case STATE_BOOLEAN:
switch(*(ptr+i))
{
case '\0':
break;
case ' ':
case '\t':
break;
case '&':
case '|':
state = STATE_NEXT;
boolean = *(ptr+i);
break;
default:
if (target_types & TARGET_SPARE)
{
/* str_start = i;*/
str_start = potential_spare_start;
state = STATE_NEXT;
target->spare = 0; /* just to ensure state is set */
break;
}
state = STATE_ERROR;
inc = 0;
break;
}
break;
case STATE_SPARE:
switch(*(ptr+i))
{
case '\0':
str_end = i;
len = str_end-str_start;
target->rt[num_targets].string = (CHARTYPE *)(*the_malloc)(len+1);
if (target->rt[num_targets].string == NULL)
{
if (allow_error_display)
display_error(30,(CHARTYPE *)"",FALSE);
#ifdef TRACE
trace_return();
#endif
return(RC_OUT_OF_MEMORY);
}
memcpy(target->rt[num_targets].string,ptr+str_start,len);
target->rt[num_targets].string[len] = '\0';
target->rt[num_targets].length = len;
target->rt[num_targets].target_type = TARGET_SPARE;
target->spare = num_targets;
num_targets++;
*(ptr+str_start) = '\0'; /* so target string does not include spare */
break;
default:
break;
}
break;
case STATE_ABSOLUTE:
case STATE_RELATIVE:
if (target->rt[num_targets].not)
{
state = STATE_ERROR;
inc = 0;
break;
}
switch(*(ptr+i))
{
case '\0':
case ' ':
case '\t':
str_end = i;
len = str_end-str_start;
target->rt[num_targets].string = (CHARTYPE *)(*the_malloc)(len+2);
if (target->rt[num_targets].string == NULL)
{
if (allow_error_display)
display_error(30,(CHARTYPE *)"",FALSE);
#ifdef TRACE
trace_return();
#endif
return(RC_OUT_OF_MEMORY);
}
if (delim != '\0')
{
target->rt[num_targets].string[0] = delim;
off = 1;
}
else
off = 0;
memcpy(target->rt[num_targets].string+off,ptr+str_start,len);
target->rt[num_targets].string[len+off] = '\0';
target->rt[num_targets].length = len+off;
target->rt[num_targets].target_type = (state == STATE_ABSOLUTE) ? TARGET_ABSOLUTE : TARGET_RELATIVE;
target->rt[num_targets].numeric_target = atol(target->rt[num_targets].string+off);
if (target->rt[num_targets].negative)
target->rt[num_targets].numeric_target *= (-1L);
if (state == STATE_ABSOLUTE)
{
if (target->rt[num_targets].numeric_target < true_line)
target->rt[num_targets].negative = TRUE;
else
target->rt[num_targets].numeric_target = min(target->rt[num_targets].numeric_target,(CURRENT_FILE->number_lines+1L));
}
else
{
if (target->rt[num_targets].negative)
target->rt[num_targets].numeric_target = max((target->rt[num_targets].numeric_target),(true_line == 0L) ? (0L) : (true_line*(-1L)));
else
target->rt[num_targets].numeric_target = min(target->rt[num_targets].numeric_target,(CURRENT_FILE->number_lines - true_line+1L));
}
potential_spare_start = i;
num_targets++;
state = STATE_BOOLEAN;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
break;
default:
state = STATE_ERROR;
inc = 0;
break;
}
break;
case STATE_NEGATIVE:
switch(*(ptr+i))
{
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
state = STATE_RELATIVE;
delim = '-';
str_start = i;
inc = 0;
break;
case '/': case '\\': case '@':
state = STATE_START;
inc = 0;
break;
case '*':
state = STATE_START;
inc = 0;
break;
case 'b': case 'B':
state = STATE_START;
inc = 0;
break;
default:
state = STATE_ERROR;
inc = 0;
break;
}
break;
case STATE_POINT:
switch(*(ptr+i))
{
case ' ':
case '\t':
state = STATE_BOOLEAN;
/* fall through */
case '&':
case '|':
case '\0':
target->rt[num_targets].target_type = TARGET_POINT;
str_end = i;
len = str_end-str_start;
target->rt[num_targets].string = (CHARTYPE *)(*the_malloc)(len+1);
if (target->rt[num_targets].string == NULL)
{
if (allow_error_display)
display_error(30,(CHARTYPE *)"",FALSE);
#ifdef TRACE
trace_return();
#endif
return(RC_OUT_OF_MEMORY);
}
memcpy(target->rt[num_targets].string,ptr+str_start,len);
target->rt[num_targets].string[len] = '\0';
target->rt[num_targets].length = len;
if (find_named_line(target->rt[num_targets].string,&lineno,TRUE) == NULL)
{
state = STATE_ERROR;
break;
}
target->rt[num_targets].numeric_target = lineno;
if (target->rt[num_targets].numeric_target < true_line)
target->rt[num_targets].negative = TRUE;
else
target->rt[num_targets].numeric_target = min(target->rt[num_targets].numeric_target,(CURRENT_FILE->number_lines+1L));
num_targets++;
potential_spare_start = i;
if (*(ptr+i) == ' ' || *(ptr+i) == '\t')
break;
boolean = *(ptr+i);
state = STATE_NEXT;
break;
default:
break;
}
break;
case STATE_ERROR:
for (j=0;j<num_targets;j++)
target->rt[j].target_type = TARGET_ERR;
state = STATE_QUIT;
break;
}
if (state == STATE_QUIT)
break;
i += inc;
if (i > target_length) /* this allows for testing '\0' as delimiter */
break;
}
target->num_targets = num_targets;
if (num_targets == 0
|| target->rt[0].target_type == TARGET_ERR)
{
if (display_parse_error
&& allow_error_display)
display_error(1,ptr,FALSE);
#ifdef TRACE
trace_return();
#endif
return(RC_INVALID_OPERAND);
}
/*---------------------------------------------------------------------*/
/* Time to validate the targets we have parsed... */
/*---------------------------------------------------------------------*/
/* Valid combinations are: */
/* TARGET_ALL (1 target only) */
/* ALL only */
/* TARGET_BLOCK (1 target only) */
/* BLOCK only */
/* this section sets target_type to TARGET_BLOCK_ANY */
/* or TARGET_BLOCK_CURRENT */
/* TARGET_BLANK (BLANK can be upper or lower case) */
/* BLANK */
/* -BLANK */
/* ~BLANK */
/* ~-BLANK */
/* TARGET_STRING (valid delimiters are / \ or @ */
/* /string/ */
/* -/string/ */
/* ~/string/ */
/* ~-/string/ */
/* TARGET_POINT */
/* .xxxxxx */
/* ~.xxxxxx */
/* TARGET_ABSOLUTE */
/* :99 */
/* ;99 */
/* TARGET_RELATIVE */
/* 99 */
/* +99 */
/* -99 */
/* * */
/* +* */
/* -* */
/* */
/* Any of the above target types may be or'd together. */
/*---------------------------------------------------------------------*/
/*---------------------------------------------------------------------*/
/* For each of the targets, check its validity... */
/*---------------------------------------------------------------------*/
negative = target->rt[0].negative;
for (i=0;i<num_targets-((target->spare == (-1)) ? 0 : 1);i++)
{
switch(target->rt[i].target_type)
{
case TARGET_BLOCK:
if (num_targets-((target->spare == (-1)) ? 0 : 1) != 1)
{
rc = RC_INVALID_OPERAND;
break;
}
if (target_types & TARGET_BLOCK_ANY)
target->rt[i].target_type = TARGET_BLOCK_ANY;
else
if (target_types & TARGET_BLOCK_CURRENT)
target->rt[i].target_type = TARGET_BLOCK_CURRENT;
else
rc = RC_INVALID_OPERAND;
break;
case TARGET_ALL:
if (num_targets-((target->spare == (-1)) ? 0 : 1) != 1)
{
rc = RC_INVALID_OPERAND;
break;
}
if (target_types & target->rt[i].target_type)
break;
rc = RC_INVALID_OPERAND;
break;
default:
if (target->rt[i].negative != negative)
{
rc = RC_INVALID_OPERAND;
break;
}
if (target_types & target->rt[i].target_type)
break;
rc = RC_INVALID_OPERAND;
break;
}
if (rc == RC_INVALID_OPERAND)
break;
}
/*---------------------------------------------------------------------*/
/* Display an error if anything found amiss and we are directed to */
/* display an error... */
/*---------------------------------------------------------------------*/
if (rc != RC_OK
&& display_parse_error
&& allow_error_display)
display_error(1,ptr,FALSE);
#ifdef TRACE
trace_return();
#endif
return(rc);
}
/***********************************************************************/
#ifdef PROTO
void initialise_target(TARGET *target)
#else
void initialise_target(target)
TARGET *target;
#endif
/***********************************************************************/
{
/*--------------------------- local data ------------------------------*/
/*--------------------------- processing ------------------------------*/
#ifdef TRACE
trace_function("target.c: initialise_target");
#endif
target->rt=NULL;
target->string=NULL;
target->num_lines = target->true_line = 0L;
target->num_targets = 0;
target->spare = (-1);
target->ignore_scope = FALSE;
#ifdef TRACE
trace_return();
#endif
return;
}
/***********************************************************************/
#ifdef PROTO
void free_target(TARGET *target)
#else
void free_target(target)
TARGET *target;
#endif
/***********************************************************************/
{
/*--------------------------- local data ------------------------------*/
register short i=0;
/*--------------------------- processing ------------------------------*/
#ifdef TRACE
trace_function("target.c: free_target");
#endif
if (target->string == NULL
&& target->num_targets == 0
&& target->rt == NULL)
{
#ifdef TRACE
trace_return();
#endif
return;
}
for (i=0;i<target->num_targets;i++)
{
if (target->rt[i].string != NULL)
(*the_free)(target->rt[i].string);
}
if (target->string != NULL)
(*the_free)(target->string);
if (target->rt != NULL)
(*the_free)(target->rt);
#ifdef TRACE
trace_return();
#endif
return;
}
/***********************************************************************/
#ifdef PROTO
short find_target(TARGET *target,LINETYPE true_line,bool display_parse_error,bool allow_error_display)
#else
short find_target(target,true_line,display_parse_error,allow_error_display)
TARGET *target;
LINETYPE true_line;
bool display_parse_error,allow_error_display;
#endif
/***********************************************************************/
{
/*-------------------------- external data ----------------------------*/
extern bool in_profile;
extern VIEW_DETAILS *vd_mark;
/*--------------------------- local data ------------------------------*/
short rc=RC_OK;
LINE *curr=NULL;
LINETYPE num_lines=0L;
LINETYPE line_number=0L;
bool status=FALSE;
/*--------------------------- processing ------------------------------*/
#ifdef TRACE
trace_function("target.c: find_target");
#endif
/*---------------------------------------------------------------------*/
/* Check single targets first (ALL and BLOCK) */
/*---------------------------------------------------------------------*/
/*---------------------------------------------------------------------*/
/* Check if first, and only target, is BLOCK... */
/*---------------------------------------------------------------------*/
switch(target->rt[0].target_type)
{
case TARGET_ALL:
target->true_line = 1L;
target->num_lines = CURRENT_FILE->number_lines;
#ifdef TRACE
trace_return();
#endif
return(RC_OK);
break;
case TARGET_BLOCK_ANY:
if (MARK_VIEW == NULL)
{
if (allow_error_display)
display_error(44,"",FALSE);
rc = RC_TARGET_NOT_FOUND;
}
else
{
target->num_lines = MARK_VIEW->mark_end_line - MARK_VIEW->mark_start_line + 1L;
target->true_line = MARK_VIEW->mark_start_line;
}
#ifdef TRACE
trace_return();
#endif
return(rc);
break;
case TARGET_BLOCK_CURRENT:
if (MARK_VIEW == NULL)
{
if (allow_error_display)
display_error(44,"",FALSE);
rc = RC_TARGET_NOT_FOUND;
}
else
{
if (MARK_VIEW != CURRENT_VIEW)
{
if (allow_error_display)
display_error(45,"",FALSE);
rc = RC_TARGET_NOT_FOUND;
}
else
{
target->num_lines = MARK_VIEW->mark_end_line - MARK_VIEW->mark_start_line + 1L;
target->true_line = MARK_VIEW->mark_start_line;
}
}
#ifdef TRACE
trace_return();
#endif
return(rc);
break;
default:
break;
}
/*---------------------------------------------------------------------*/
/* All other targets are potentially repeating targets... */
/*---------------------------------------------------------------------*/
rc = RC_TARGET_NOT_FOUND;
status = FALSE;
line_number = true_line;
curr = lll_find(CURRENT_FILE->first_line,true_line);
num_lines = 0L;
while(1)
{
status = find_rtarget_target(curr,target,true_line,line_number,&num_lines);
if (status)
break;
/*---------------------------------------------------------------------*/
/* We can determine the direction of execution based on the first */
/* target, as all targets must have the same direction to have reached */
/* here. */
/*---------------------------------------------------------------------*/
if (target->rt[0].negative)
{
curr = curr->prev;
line_number--;
}
else
{
curr = curr->next;
line_number++;
}
if (curr == NULL)
break;
}
if (status)
{
num_lines = ((target->rt[0].negative) ? -num_lines : num_lines);
target->num_lines = num_lines;
target->true_line = true_line;
rc = RC_OK;
}
else
{
if (allow_error_display)
display_error(17,target->string,FALSE);
rc = RC_TARGET_NOT_FOUND;
}
#ifdef TRACE
trace_return();
#endif
return(rc);
}
/***********************************************************************/
#ifdef PROTO
static bool is_blank(LINE *curr)
#else
static bool is_blank(curr)
LINE *curr;
#endif
/***********************************************************************/
{
/*-------------------------- external data ----------------------------*/
/*--------------------------- local data ------------------------------*/
register short i=0;
bool rc=TRUE;
/*--------------------------- processing ------------------------------*/
#ifdef TRACE
trace_function("target.c: is_blank");
#endif
if (CURRENT_VIEW->zone_start > curr->length)
{
#ifdef TRACE
trace_return();
#endif
return(TRUE);
}
for (i=CURRENT_VIEW->zone_start-1;i<min(CURRENT_VIEW->zone_end,curr->length);i++)
{
if (*(curr->line+i) != ' ')
{
rc = FALSE;
break;
}
}
#ifdef TRACE
trace_return();
#endif
return(rc);
}
/***********************************************************************/
#ifdef PROTO
LINE *find_named_line(CHARTYPE *name,LINETYPE *retline,bool respect_scope)
#else
LINE *find_named_line(name,retline,respect_scope)
CHARTYPE *name;
LINETYPE *retline;
bool respect_scope;
#endif
/***********************************************************************/
{
/*-------------------------- external data ----------------------------*/
/*--------------------------- local data ------------------------------*/
LINETYPE lineno=0;
LINE *curr=NULL;
/*--------------------------- processing ------------------------------*/
#ifdef TRACE
trace_function("target.c: find_named_line");
#endif
/*---------------------------------------------------------------------*/
/* Find the line number in the current file of the named line specified*/
/*---------------------------------------------------------------------*/
curr = CURRENT_FILE->first_line;
while(curr->next != (LINE *)NULL)
{
/*---------------------------------------------------------------------*/
/* Check the line's name if we are not respecting scope or if we are */
/* respecting scope and the line is in scope. */
/*---------------------------------------------------------------------*/
if (!respect_scope
|| (respect_scope && (in_scope(curr) || CURRENT_VIEW->scope_all)))
{
if (curr->name != (CHARTYPE *)NULL)
if (strcmp(curr->name,name) == 0)
{
#ifdef TRACE
trace_return();
#endif
*retline = lineno;
return(curr);
}
}
lineno++;
curr = curr->next;
}
#ifdef TRACE
trace_return();
#endif
return((LINE *)NULL);
}
/***********************************************************************/
#ifdef PROTO
short find_string_target(LINE *curr,RTARGET *rt)
#else
short find_string_target(curr,rt)
LINE *curr;
RTARGET *rt;
#endif
/***********************************************************************/
{
/*-------------------------- external data ----------------------------*/
extern CHARTYPE *rec;
/*--------------------------- local data ------------------------------*/
CHARTYPE *needle=(CHARTYPE *)rt->string;
CHARTYPE *haystack=curr->line;
LENGTHTYPE needle_length=0,haystack_length=0,real_start=0,real_end=0;
bool use_rec=FALSE;
short rc=RC_OK;
short loc=0;
/*--------------------------- processing ------------------------------*/
#ifdef TRACE
trace_function("target.c: find_string_target");
#endif
/*---------------------------------------------------------------------*/
/* Copy contents of rec into linked to ensure that changes made are */
/* included in the linked list searched. */
/*---------------------------------------------------------------------*/
post_process_line(CURRENT_VIEW,CURRENT_VIEW->focus_line);
/*---------------------------------------------------------------------*/
/* If HEX is on, convert the target from a HEX format to CHARTYPE. */
/*---------------------------------------------------------------------*/
if (CURRENT_VIEW->hex == TRUE)
{
rc = convert_hex_strings(needle);
if (rc == (-1))
{
display_error(32,(CHARTYPE *)"",FALSE);
#ifdef TRACE
trace_return();
#endif
return(RC_INVALID_OPERAND);
}
else
needle_length = rc;
}
else
needle_length = strlen(needle);
/*---------------------------------------------------------------------*/
/* Determine if we need to copy the contents of the line into rec. */
/* The reasons we need to do this are: */
/* - the length of the needle is 0 */
/* - the last character of needle is a space */
/*---------------------------------------------------------------------*/
if (needle_length == 0)
use_rec = TRUE;
else
if (*(needle+(needle_length-1)) == ' ')
use_rec = TRUE;
if (use_rec)
{
memset(rec,' ',max_line_length);
memcpy(rec,curr->line,curr->length);
haystack = rec;
haystack_length = max_line_length;
}
else
{
haystack = curr->line;
haystack_length = curr->length;
}
/*---------------------------------------------------------------------*/
/* Calculate the bounds to search in based on length of haystack and */
/* ZONE settings. */
/*---------------------------------------------------------------------*/
real_end = min(haystack_length,CURRENT_VIEW->zone_end-1);
real_start = max(0,CURRENT_VIEW->zone_start-1);
/*---------------------------------------------------------------------*/
/* Find the needle in the haystack. */
/*---------------------------------------------------------------------*/
loc = memfind(haystack+real_start,needle,(real_end-real_start+1),
needle_length,(CURRENT_VIEW->case_locate == CASE_IGNORE) ? TRUE : FALSE,
CURRENT_VIEW->arbchar_status,
CURRENT_VIEW->arbchar_single,
CURRENT_VIEW->arbchar_multiple);
if (loc == (-1))
rc = RC_TARGET_NOT_FOUND;
else
rc = RC_OK;
/*---------------------------------------------------------------------*/
/* Copy contents of linked list into rec if we have used rec as a work */
/* area. */
/*---------------------------------------------------------------------*/
if (use_rec)
pre_process_line(CURRENT_VIEW,CURRENT_VIEW->focus_line);
#ifdef TRACE
trace_return();
#endif
return(rc);
}
/***********************************************************************/
#ifdef PROTO
bool find_rtarget_target(LINE *curr,TARGET *target,LINETYPE true_line,LINETYPE line_number,LINETYPE *num_lines)
#else
bool find_rtarget_target(curr,target,true_line,line_number,num_lines)
LINE *curr;
TARGET *target;
LINETYPE true_line,line_number;
LINETYPE *num_lines;
#endif
/***********************************************************************/
{
/*-------------------------- external data ----------------------------*/
/*--------------------------- local data ------------------------------*/
register short i=0;
bool target_found=FALSE,status=FALSE;
LINETYPE multiplier=0;
/*--------------------------- processing ------------------------------*/
#ifdef TRACE
trace_function("target.c: find_rtarget_target");
#endif
/*---------------------------------------------------------------------*/
/* If the line is not in scope and scope is respected, return FALSE. */
/*---------------------------------------------------------------------*/
if (!(in_scope(curr))
&& !target->ignore_scope)
{
if (!CURRENT_VIEW->scope_all
&& !TOF(line_number)
&& !BOF(line_number))
{
#ifdef TRACE
trace_return();
#endif
return(FALSE);
}
}
if (line_number != true_line)
*num_lines = *num_lines + 1L;
for (i=0;i<target->num_targets-((target->spare == (-1)) ? 0 : 1);i++)
{
target_found = FALSE;
multiplier = (target->rt[i].negative) ? -1L : 1L;
switch(target->rt[i].target_type)
{
case TARGET_BLANK:
if (true_line == line_number)
{
target_found = ((target->rt[i].not) ? TRUE : FALSE);
break;
}
if (target->rt[0].negative)
{
if (curr->prev == NULL)
break;
}
else
{
if (curr->next == NULL)
break;
}
target_found = is_blank(curr);
break;
case TARGET_POINT:
if (true_line == line_number)
{
target_found = ((target->rt[i].not) ? TRUE : FALSE);
break;
}
if (curr->name == (CHARTYPE *)NULL)
break;
if (strcmp(curr->name,target->rt[i].string) == 0)
target_found = TRUE;
break;
case TARGET_STRING:
if (true_line == line_number)
{
target_found = ((target->rt[i].not) ? TRUE : FALSE);
break;
}
if (target->rt[0].negative)
{
if (curr->prev == NULL)
break;
}
else
{
if (curr->next == NULL)
break;
}
if (find_string_target(curr,&target->rt[i]) == RC_OK)
target_found = TRUE;
break;
case TARGET_RELATIVE:
if ((*num_lines * multiplier) == target->rt[i].numeric_target)
target_found = TRUE;
if (target->rt[0].negative)
{
if (curr->prev == NULL)
{
target_found = TRUE;
break;
}
}
else
{
if (curr->next == NULL)
{
target_found = TRUE;
break;
}
}
break;
case TARGET_ABSOLUTE:
if (line_number == target->rt[i].numeric_target)
target_found = TRUE;
break;
default:
break;
}
if (target->rt[i].not)
target_found = (target_found) ? FALSE : TRUE;
switch(target->rt[i].boolean)
{
case ' ':
status = target_found;
break;
case '&':
status &= target_found;
break;
case '|':
status |= target_found;
break;
}
}
#ifdef TRACE
trace_return();
#endif
return(status);
}
/***********************************************************************/
#ifdef PROTO
LINETYPE find_next_in_scope(LINE *in_curr,LINETYPE line_number,short direction)
#else
LINETYPE find_next_in_scope(in_curr,line_number,direction)
LINE *in_curr;
LINETYPE line_number;
short direction;
#endif
/***********************************************************************/
{
/*-------------------------- external data ----------------------------*/
/*--------------------------- local data ------------------------------*/
LINE *curr=in_curr;
/*--------------------------- processing ------------------------------*/
#ifdef TRACE
trace_function("target.c: find_next_in_scope");
#endif
if (in_curr == NULL)
curr = lll_find(CURRENT_FILE->first_line,line_number);
for (;;line_number+=(LINETYPE)direction)
{
if (in_scope(curr))
break;
if (direction == DIRECTION_FORWARD)
curr = curr->next;
else
curr = curr->prev;
if (curr == NULL)
break;
}
#ifdef TRACE
trace_return();
#endif
return(line_number);
}
/***********************************************************************/
#ifdef PROTO
LINETYPE find_last_not_in_scope(LINE *in_curr,LINETYPE line_number,short direction)
#else
LINETYPE find_last_not_in_scope(in_curr,line_number,direction)
LINE *in_curr;
LINETYPE line_number;
short direction;
#endif
/***********************************************************************/
{
/*-------------------------- external data ----------------------------*/
/*--------------------------- local data ------------------------------*/
LINE *curr=in_curr;
LINETYPE offset=0L;
/*--------------------------- processing ------------------------------*/
#ifdef TRACE
trace_function("target.c: find_last_not_in_scope");
#endif
if (in_curr == NULL)
curr = lll_find(CURRENT_FILE->first_line,line_number);
for (;;line_number+=(LINETYPE)direction)
{
if (in_scope(curr))
break;
if (direction == DIRECTION_FORWARD)
{
curr = curr->next;
offset = (-1L);
}
else
{
curr = curr->prev;
offset = 1L;
}
if (curr == NULL)
break;
}
#ifdef TRACE
trace_return();
#endif
return(line_number+offset);
}
/***********************************************************************/
#ifdef PROTO
short validate_target(CHARTYPE *string,TARGET *target,short target_type,LINETYPE true_line,bool display_parse_error,bool allow_error_display)
#else
short validate_target(string,target,target_type,true_line,display_parse_error,allow_error_display)
CHARTYPE *string;
TARGET *target;
short target_type;
LINETYPE true_line;
bool display_parse_error,allow_error_display;
#endif
/***********************************************************************/
{
/*-------------------------- external data ----------------------------*/
/*--------------------------- local data ------------------------------*/
short rc=RC_OK;
/*--------------------------- processing ------------------------------*/
#ifdef TRACE
trace_function("target.c: validate_target");
#endif
rc = parse_target(string,true_line,target,target_type,display_parse_error,allow_error_display);
if (rc != RC_OK)
{
#ifdef TRACE
trace_return();
#endif
return(RC_INVALID_OPERAND);
}
rc = find_target(target,true_line,display_parse_error,allow_error_display);
if (rc != RC_OK)
{
#ifdef TRACE
trace_return();
#endif
return(RC_TARGET_NOT_FOUND);
}
#ifdef TRACE
trace_return();
#endif
return(RC_OK);
}
/***********************************************************************/
#ifdef PROTO
bool in_scope(LINE *curr)
#else
bool in_scope(curr)
LINE *curr;
#endif
/***********************************************************************/
{
/*-------------------------- external data ----------------------------*/
/*--------------------------- local data ------------------------------*/
bool rc=RC_OK;
/*--------------------------- processing ------------------------------*/
#ifdef TRACE
trace_function("target.c: in_scope");
#endif
if (curr->select < CURRENT_VIEW->display_low
|| curr->select > CURRENT_VIEW->display_high)
rc = FALSE;
else
rc = TRUE;
#ifdef TRACE
trace_return();
#endif
return(rc);
}
/***********************************************************************/
#ifdef PROTO
void calculate_scroll_values(short *number_focus_rows,LINETYPE *new_focus_line,
LINETYPE *new_current_line,bool *limit_of_screen,
bool *limit_of_file,bool *leave_cursor,
short direction)
#else
void calculate_scroll_values(number_focus_rows,new_focus_line,new_current_line,
limit_of_screen,limit_of_file,leave_cursor,direction)
short *number_focus_rows;
LINETYPE *new_focus_line,*new_current_line;
bool *limit_of_screen,*limit_of_file,*leave_cursor;
short direction;
#endif
/***********************************************************************/
{
/*------------------------- external data -----------------------------*/
/*--------------------------- local data ------------------------------*/
register short i=0;
unsigned short x=0,y=0;
/*--------------------------- processing ------------------------------*/
#ifdef TRACE
trace_function("target.c: calculate_scroll_values");
#endif
/* getyx(CURRENT_WINDOW,y,x);*/
*limit_of_screen = *limit_of_file = FALSE;
*number_focus_rows = 0;
*new_focus_line = (-1L);
y = CURRENT_SCREEN.rows[WINDOW_MAIN];
switch(direction)
{
case DIRECTION_FORWARD:
/*---------------------------------------------------------------------*/
/* Determine the new focus line and the number of rows to adjust the */
/* cursor position. */
/*---------------------------------------------------------------------*/
for (i=0;i<CURRENT_SCREEN.rows[WINDOW_MAIN];i++)
{
if (CURRENT_SCREEN.sl[i].line_number == CURRENT_VIEW->focus_line)
{
y = i;
continue;
}
if (CURRENT_SCREEN.sl[i].line_number != (-1L)
&& y != CURRENT_SCREEN.rows[WINDOW_MAIN])
{
*number_focus_rows = i-y;
*new_focus_line = CURRENT_SCREEN.sl[i].line_number;
break;
}
}
/*---------------------------------------------------------------------*/
/* If we have NOT set a new focus line (because we are on the bottom */
/* of the screen) the new focus line is the next line in scope (if */
/* SHADOW is OFF). If SHADOW is ON, the new focus line is determined by*/
/* the status of the current focus line. */
/*---------------------------------------------------------------------*/
if (*new_focus_line == (-1L))
{
if (CURRENT_VIEW->shadow)
{
*new_focus_line = CURRENT_SCREEN.sl[y].line_number +
((CURRENT_SCREEN.sl[y].number_lines_excluded == 0) ?
1L :
(LINETYPE)CURRENT_SCREEN.sl[y].number_lines_excluded);
}
else
{
if (CURRENT_SCREEN.sl[y].current->next != NULL)
*new_focus_line = find_next_in_scope(CURRENT_SCREEN.sl[y].current->next,
CURRENT_SCREEN.sl[y].line_number+1L,direction);
}
}
/*---------------------------------------------------------------------*/
/* Determine the new current line and the number of rows to adjust the */
/* cursor position. */
/*---------------------------------------------------------------------*/
*leave_cursor = TRUE;
*new_current_line = (-1L);
for (i=CURRENT_VIEW->current_row+1;i<CURRENT_SCREEN.rows[WINDOW_MAIN];i++)
{
if (CURRENT_SCREEN.sl[i].line_type == LINE_LINE
|| CURRENT_SCREEN.sl[i].line_type == LINE_TOF_EOF)
{
*new_current_line = CURRENT_SCREEN.sl[i].line_number;
break;
}
if (CURRENT_SCREEN.sl[i].line_type == LINE_SHADOW)
*leave_cursor = FALSE;
}
/*---------------------------------------------------------------------*/
/* If we have NOT set a new current line (only way this can happen is */
/* if all lines after the current line are RESERVED, SCALE or TABLINE) */
/* and the cursor is on the current line) the new current line is the */
/* next line in scope. */
/*---------------------------------------------------------------------*/
if (*new_current_line == (-1L))
{
if (CURRENT_SCREEN.sl[y].current->next != NULL)
*new_current_line = find_next_in_scope(CURRENT_SCREEN.sl[y].current->next,
CURRENT_SCREEN.sl[y].line_number+1L,direction);
}
/*---------------------------------------------------------------------*/
/* Set flags for bottom_of_screen and bottom_of_file as appropriate. */
/*---------------------------------------------------------------------*/
if (*number_focus_rows == 0)
*limit_of_screen = TRUE;
if (CURRENT_SCREEN.sl[y].line_type == LINE_TOF_EOF
&& CURRENT_SCREEN.sl[y].current->next == NULL)
*limit_of_file = TRUE;
break;
case DIRECTION_BACKWARD:
/*---------------------------------------------------------------------*/
/* Determine the new focus line and the number of rows to adjust the */
/* cursor position. */
/*---------------------------------------------------------------------*/
for (i=CURRENT_SCREEN.rows[WINDOW_MAIN]-1;i>-1;i--)
{
if (CURRENT_SCREEN.sl[i].line_number == CURRENT_VIEW->focus_line)
{
y = i;
continue;
}
if (CURRENT_SCREEN.sl[i].line_number != (-1L)
&& y != CURRENT_SCREEN.rows[WINDOW_MAIN])
{
*number_focus_rows = y-i;
*new_focus_line = CURRENT_SCREEN.sl[i].line_number;
break;
}
}
/*---------------------------------------------------------------------*/
/* If we have NOT set a new focus line (because we are on the top */
/* of the screen) the new focus line is the prev line in scope (if */
/* SHADOW is OFF). If SHADOW is ON, the new focus line is determined by*/
/* the status of the current focus line. */
/*---------------------------------------------------------------------*/
if (*new_focus_line == (-1L))
{
if (CURRENT_VIEW->shadow)
{
if (CURRENT_SCREEN.sl[y].line_type == LINE_SHADOW)
*new_focus_line = CURRENT_SCREEN.sl[y].line_number - 1L;
else
{
if (CURRENT_SCREEN.sl[y].current->prev != NULL)
{
*new_focus_line = find_next_in_scope(CURRENT_SCREEN.sl[y].current->prev,
CURRENT_SCREEN.sl[y].line_number-1L,direction);
if (*new_focus_line != CURRENT_SCREEN.sl[y].line_number-1L)
*new_focus_line++;
}
}
}
else
{
if (CURRENT_SCREEN.sl[y].current->prev != NULL)
*new_focus_line = find_next_in_scope(CURRENT_SCREEN.sl[y].current->prev,
CURRENT_SCREEN.sl[y].line_number-1L,direction);
}
}
/*---------------------------------------------------------------------*/
/* Determine the new current line and the number of rows to adjust the */
/* cursor position. */
/*---------------------------------------------------------------------*/
*leave_cursor = TRUE;
*new_current_line = (-1L);
for (i=CURRENT_VIEW->current_row-1;i>-1;i--)
{
if (CURRENT_SCREEN.sl[i].line_type == LINE_LINE
|| CURRENT_SCREEN.sl[i].line_type == LINE_TOF_EOF)
{
*new_current_line = CURRENT_SCREEN.sl[i].line_number;
break;
}
if (CURRENT_SCREEN.sl[i].line_type == LINE_SHADOW)
*leave_cursor = FALSE;
}
/*---------------------------------------------------------------------*/
/* If we have NOT set a new current line (only way this can happen is */
/* if all lines before the current line are RESERVED, SCALE or TABLINE)*/
/* and the cursor is on the current line) the new current line is the */
/* previous line in scope. */
/*---------------------------------------------------------------------*/
if (*new_current_line == (-1L))
{
if (CURRENT_SCREEN.sl[y].current->prev != NULL)
*new_current_line = find_next_in_scope(CURRENT_SCREEN.sl[y].current->prev,
CURRENT_SCREEN.sl[y].line_number-1L,direction);
}
/*---------------------------------------------------------------------*/
/* Set flags for top_of_screen and top_of_file as appropriate. */
/*---------------------------------------------------------------------*/
if (*number_focus_rows == 0)
*limit_of_screen = TRUE;
if (CURRENT_SCREEN.sl[y].line_type == LINE_TOF_EOF
&& CURRENT_SCREEN.sl[y].current->prev == NULL)
*limit_of_file = TRUE;
break;
}
#ifdef TRACE
trace_return();
#endif
return;
}
/***********************************************************************/
#ifdef PROTO
short find_last_focus_line(unsigned short *newrow)
#else
short find_last_focus_line(newrow)
unsigned short *newrow;
#endif
/***********************************************************************/
{
/*------------------------- external data -----------------------------*/
/*--------------------------- local data ------------------------------*/
register short i=0;
short row=(-1);
short rc=RC_OK;
/*--------------------------- processing ------------------------------*/
#ifdef TRACE
trace_function("target.c: find_last_focus_line");
#endif
for (i=CURRENT_SCREEN.rows[WINDOW_MAIN]-1;i>-1;i--)
{
if (CURRENT_SCREEN.sl[i].line_number != (-1L))
{
*newrow = row = i;
break;
}
}
if (row == (-1))
rc = RC_INVALID_OPERAND;
#ifdef TRACE
trace_return();
#endif
return(rc);
}
/***********************************************************************/
#ifdef PROTO
short find_first_focus_line(unsigned short *newrow)
#else
short find_first_focus_line(newrow)
unsigned short *newrow;
#endif
/***********************************************************************/
{
/*------------------------- external data -----------------------------*/
/*--------------------------- local data ------------------------------*/
register short i=0;
short row=(-1);
short rc=RC_OK;
/*--------------------------- processing ------------------------------*/
#ifdef TRACE
trace_function("target.c: find_first_focus_line");
#endif
for (i=0;i<CURRENT_SCREEN.rows[WINDOW_MAIN];i++)
{
if (CURRENT_SCREEN.sl[i].line_number != (-1L))
{
*newrow = row = i;
break;
}
}
if (row == (-1))
rc = RC_INVALID_OPERAND;
#ifdef TRACE
trace_return();
#endif
return(rc);
}